Note: This analysis requires input data generated by an earlier script.

Setup

  • Clear memory and console
  • Load packages
  • Get current script name
# Clear memory
rm(list=setdiff(ls(all=TRUE), c(".Random.seed")))
# Clear console
cat("\014")

Set up

this.script <- rstudioapi::getActiveDocumentContext()$path %>% basename
cat("Script:", this.script)
Script: 06_Figure_S1.Rmd
gg.get.breaks_by1 <- function(limits) {
  a <- floor(limits[1])
  b <- ceiling(limits[2])
  seq(a, b, by = 1)
}

gg.get.breaks_by2 <- function(limits) {
  a <- floor(limits[1])
  if (a %% 2 == 1) a <- a - 1
  b <- ceiling(limits[2])
  if (b %% 2 == 1) b <- b + 1
  seq(a, b, by = 2)
}
get.gg <- function(mtrx, colum.names, axis.labs, titre,
                    marker.col.false, marker.col.true="#B20000", marker.alpha=1, ttable) {

  ttable2 <- dplyr::select(ttable, PROBEID, SYMBOL, adj.P.Val) %>% 
    dplyr::group_by(PROBEID) %>%
    dplyr::slice(which.min(adj.P.Val)) %>% 
    dplyr::ungroup(.)

  df <- mtrx[,colum.names] %>% 
    magrittr::set_colnames(axis.labs) %>% 
    tibble::rownames_to_column("PROBEID")
  
  df2 <- merge(x=ttable2, y=df, by="PROBEID", all.x=FALSE, all.y=TRUE) %>% 
    dplyr::mutate(p.ok = adj.P.Val <= 0.05) %>% 
    dplyr::mutate(p.ok = as.character(p.ok)) %>% 
    dplyr::mutate(p.ok = factor(p.ok, levels=c("FALSE", "TRUE"))) %>% 
    dplyr::mutate(ID = paste0(SYMBOL, " (", PROBEID, ")")) %>% 
    dplyr::select(-PROBEID, -SYMBOL, -adj.P.Val) %>% 
    dplyr::select(ID, everything())

  res <- df2 %>% 
    ggplot(aes_string(x=axis.labs[1], y=axis.labs[2])) +
    geom_point(aes(text=ID, color=p.ok), alpha=marker.alpha) + # color=marker.col.false,
    # scale_color_discrete(name="p ≤ 0.05") +
    scale_color_manual(values=c(marker.col.false, marker.col.true), name="p ≤ 0.05") +
    scale_x_continuous(limits =c(min(mtrx), max(mtrx))) +
    scale_y_continuous(limits =c(min(mtrx), max(mtrx))) +
    geom_abline(intercept = 0, slope = 1, color="grey25") +
    geom_abline(intercept = -log2(1.75), slope = 1, color="grey25", linetype="dashed") +
    geom_abline(intercept = log2(1.75), slope = 1, color="grey25", linetype="dashed") +
    labs(title = titre)
  res
}

Load data

Load mean expression data

Table includes probe IDs, gene symbols and gene names.
Probe IDs and symbols are not unique (due to gene symbol mapping).

mean.expr.file <- "./data/01_Raw_Data_Processing.Rmd.expr_mean.txt"
matrix.df.mean <- read.table(mean.expr.file, sep="\t", header=T,
                             stringsAsFactors = FALSE) %>% 
  dplyr::select(-SYMBOL, -GENENAME) %>% 
  dplyr::distinct(PROBEID, .keep_all=TRUE) %>% 
  tibble::column_to_rownames("PROBEID")
cat("File read:", mean.expr.file)
File read: ./data/01_Raw_Data_Processing.Rmd.expr_mean.txt
rm(mean.expr.file)

Load differentially expressed probes (effect of MMS)

# list.files("data")
diff.probes.file <- "./data/02_Suppl_Table_01.Rmd.DEprobes.RDS"
stopifnot(file.exists(diff.probes.file))
test.results.probes <- readRDS(diff.probes.file)
cat("File read:", diff.probes.file)
File read: ./data/02_Suppl_Table_01.Rmd.DEprobes.RDS
rm(diff.probes.file)
x <- paste(utils::capture.output(str(test.results.probes)), collapse="<br>\n", sep="")
details::details(x, summary="Show summary of DE probes", lang=NULL)
Show summary of DE probes

List of 4
$ ko.ctrl.vs.wt.ctrl:List of 3
..$ down : chr [1:5] “1419620_at” “1424105_a_at” “1425771_at” “1438390_s_at” …
..$ up : chr [1:4] “1416958_at” “1426230_at” “1426464_at” “1438211_s_at”
..$ total: chr [1:9] “1416958_at” “1419620_at” “1424105_a_at” “1425771_at” …
$ ko.mms.vs.wt.mms :List of 3
..$ down : chr [1:3] “1419620_at” “1424105_a_at” “1438390_s_at”
..$ up : chr “1455530_at”
..$ total: chr [1:4] “1419620_at” “1424105_a_at” “1438390_s_at” “1455530_at”
$ wt.mms.vs.wt.ctrl :List of 3
..$ down : chr [1:584] “1415743_at” “1415802_at” “1415810_at” “1415822_at” …
..$ up : chr [1:232] “1416029_at” “1416108_a_at” “1416235_at” “1416432_at” …
..$ total: chr [1:816] “1415743_at” “1415802_at” “1415810_at” “1415822_at” …
$ ko.mms.vs.ko.ctrl :List of 3
..$ down : chr [1:105] “1415972_at” “1416158_at” “1417020_at” “1417073_a_at” …
..$ up : chr [1:115] “1415817_s_at” “1416100_at” “1416172_at” “1416347_at” …
..$ total: chr [1:220] “1415817_s_at” “1415972_at” “1416100_at” “1416158_at” …


rm(x)

Load toptables

# list.files()
tt.file <- "Supplemental_Data_1.xlsx"
stopifnot(file.exists(tt.file))
tt.sheet.names <- openxlsx::getSheetNames(tt.file)
# tt.sheet.names
# "ko.ctrl.vs.wt.ctrl" "ko.mms.vs.wt.mms"   "wt.mms.vs.wt.ctrl"  "ko.mms.vs.ko.ctrl"
get.xlsx.data <- function(fil, sheet) {
  openxlsx::read.xlsx(xlsxFile = fil, sheet=sheet)
}
tt.list <- lapply(tt.sheet.names, function(the.sheet) {
  res <- get.xlsx.data(fil=tt.file, sheet=the.sheet) %>% 
    dplyr::select(PROBEID, SYMBOL, logFC, adj.P.Val)
  res
}) %>% 
  set_names(tt.sheet.names)
cat("File read:", tt.file)
File read: Supplemental_Data_1.xlsx
rm(tt.file, tt.sheet.names)
y <- paste(utils::capture.output(str(tt.list)), collapse="<br>\n", sep="")
details::details(y, summary="Show summary of toptables list", lang=NULL)
Show summary of toptables list

List of 4
$ ko.ctrl.vs.wt.ctrl:‘data.frame’: 24491 obs. of 4 variables:
..$ PROBEID : chr [1:24491] “1439200_x_at” “1426464_at” “1438211_s_at” “1455265_a_at” …
..$ SYMBOL : chr [1:24491] “Rhox4b” “Nr1d1” “Dbp” “Rgs16” …
..$ logFC : num [1:24491] 4.19 3.6 3.36 3.33 3.26 …
..$ adj.P.Val: num [1:24491] 0.35717 0.00159 0.04513 0.41762 0.50034 …
$ ko.mms.vs.wt.mms :‘data.frame’: 24491 obs. of 4 variables:
..$ PROBEID : chr [1:24491] “1439200_x_at” “1415905_at” “1434137_x_at” “1448964_at” …
..$ SYMBOL : chr [1:24491] “Rhox4b” “Reg1” “Zg16” “S100g” …
..$ logFC : num [1:24491] 4 3.48 3.42 2.97 2.47 …
..$ adj.P.Val: num [1:24491] 0.0941 0.1387 0.2036 0.1737 0.3266 …
$ wt.mms.vs.wt.ctrl :‘data.frame’: 24491 obs. of 4 variables:
..$ PROBEID : chr [1:24491] “1438211_s_at” “1428942_at” “1455265_a_at” “1449233_at” …
..$ SYMBOL : chr [1:24491] “Dbp” “Mt2” “Rgs16” “Bhlha15” …
..$ logFC : num [1:24491] 4.33 4.23 4.2 4.17 4 …
..$ adj.P.Val: num [1:24491] 0.00214 0.00594 0.01936 0.02318 0.00214 …
$ ko.mms.vs.ko.ctrl :‘data.frame’: 24491 obs. of 4 variables:
..$ PROBEID : chr [1:24491] “1415905_at” “1448964_at” “1418287_a_at” “1434137_x_at” …
..$ SYMBOL : chr [1:24491] “Reg1” “S100g” “Dmbt1” “Zg16” …
..$ logFC : num [1:24491] 4.15 3.91 3.48 3.46 3.39 …
..$ adj.P.Val: num [1:24491] 0.0582 0.0638 0.0832 0.129 0.1372 …


rm(y)

Plot probes suppressed OR induced by MMS in wild-type OR knockout

Select probes to plot

wt.ko.down.up <- sort(unique(unlist(test.results.probes)))
stopifnot(!any(is.na(wt.ko.down.up)))
cat("Probes selected:", length(wt.ko.down.up))
Probes selected: 980
# matrix.df.mean[1:4,1:4]
mx.wt.ko.down.up <- matrix.df.mean[wt.ko.down.up,]
dim(mx.wt.ko.down.up)
gg.6.4 <- get.gg(mtrx=mx.wt.ko.down.up,
       colum.names = c("Wt_Ctrl", "Ko_Ctrl"),
       axis.labs = c("WT", "KO"),
       titre = "Control: Knockout versus Wild-type",
       marker.col.false = "#005AB5", # bp[3]
       marker.col.true = "#DC3220",
       marker.alpha=0.5,
       ttable=tt.list$ko.ctrl.vs.wt.ctrl)
gg.6.4b <- gg.6.4 + 
  theme_classic() +
  coord_equal()
ggplotly(gg.6.4b)
out.file.pdf <- "Figure_S1.pdf"
ggsave(filename=out.file.pdf, plot = gg.6.4b, width = 10, height=10, units = "cm")
cat("Saved:", out.file.pdf)
Saved: Figure_S1.pdf

Session info

cat("Date:", format(Sys.time(), "%a %d-%b-%Y %H:%M:%S"), "<br>\n")

Date: Sun 28-Mar-2021 22:49:25

devtools::session_info()
─ Session info ────────────────────────────────────────────────────────────────────────────────────────────────────

─ Packages ────────────────────────────────────────────────────────────────────────────────────────────────────────
 package        * version date       lib source        
 affy             1.64.0  2019-10-29 [1] Bioconductor  
 affyio           1.56.0  2019-10-29 [1] Bioconductor  
 AnnotationDbi  * 1.48.0  2019-10-29 [1] Bioconductor  
 assertthat       0.2.1   2019-03-21 [1] CRAN (R 3.6.1)
 Biobase        * 2.46.0  2019-10-29 [1] Bioconductor  
 BiocGenerics   * 0.32.0  2019-10-29 [1] Bioconductor  
 BiocManager      1.30.12 2021-03-28 [1] CRAN (R 3.6.1)
 bit              4.0.4   2020-08-04 [1] CRAN (R 3.6.1)
 bit64            4.0.5   2020-08-30 [1] CRAN (R 3.6.1)
 blob             1.2.1   2020-01-20 [1] CRAN (R 3.6.1)
 bslib            0.2.4   2021-01-25 [1] CRAN (R 3.6.1)
 cachem           1.0.4   2021-02-13 [1] CRAN (R 3.6.1)
 callr            3.6.0   2021-03-28 [1] CRAN (R 3.6.1)
 cellranger       1.1.0   2016-07-27 [1] CRAN (R 3.6.1)
 cli              2.3.1   2021-02-23 [1] CRAN (R 3.6.1)
 clipr            0.7.1   2020-10-08 [1] CRAN (R 3.6.1)
 codetools        0.2-16  2018-12-24 [2] CRAN (R 3.6.1)
 colorspace       2.0-0   2020-11-11 [1] CRAN (R 3.6.1)
 crayon           1.4.1   2021-02-08 [1] CRAN (R 3.6.1)
 crosstalk        1.1.1   2021-01-12 [1] CRAN (R 3.6.1)
 data.table       1.14.0  2021-02-21 [1] CRAN (R 3.6.1)
 DBI              1.1.1   2021-01-15 [1] CRAN (R 3.6.1)
 desc             1.3.0   2021-03-05 [1] CRAN (R 3.6.1)
 details          0.2.1   2020-01-12 [1] CRAN (R 3.6.1)
 devtools         2.3.2   2020-09-18 [1] CRAN (R 3.6.1)
 digest           0.6.27  2020-10-24 [1] CRAN (R 3.6.1)
 dplyr          * 1.0.5   2021-03-05 [1] CRAN (R 3.6.1)
 DT               0.17    2021-01-06 [1] CRAN (R 3.6.1)
 ellipsis         0.3.1   2020-05-15 [1] CRAN (R 3.6.1)
 evaluate         0.14    2019-05-28 [1] CRAN (R 3.6.1)
 fansi            0.4.2   2021-01-15 [1] CRAN (R 3.6.1)
 farver           2.1.0   2021-02-28 [1] CRAN (R 3.6.1)
 fastmap          1.1.0   2021-01-25 [1] CRAN (R 3.6.1)
 fs               1.5.0   2020-07-31 [1] CRAN (R 3.6.1)
 generics         0.1.0   2020-10-31 [1] CRAN (R 3.6.1)
 ggplot2        * 3.3.3   2020-12-30 [1] CRAN (R 3.6.1)
 glue             1.4.2   2020-08-27 [1] CRAN (R 3.6.1)
 gridExtra        2.3     2017-09-09 [1] CRAN (R 3.6.1)
 gtable           0.3.0   2019-03-25 [1] CRAN (R 3.6.1)
 htmltools        0.5.1.1 2021-01-22 [1] CRAN (R 3.6.1)
 htmlwidgets      1.5.3   2020-12-10 [1] CRAN (R 3.6.1)
 httr             1.4.2   2020-07-20 [1] CRAN (R 3.6.1)
 IRanges        * 2.20.2  2020-01-13 [1] Bioconductor  
 jquerylib        0.1.3   2020-12-17 [1] CRAN (R 3.6.1)
 jsonlite         1.7.2   2020-12-09 [1] CRAN (R 3.6.1)
 knitr            1.31    2021-01-27 [1] CRAN (R 3.6.1)
 labeling         0.4.2   2020-10-20 [1] CRAN (R 3.6.1)
 lazyeval         0.2.2   2019-03-15 [1] CRAN (R 3.6.1)
 lifecycle        1.0.0   2021-02-15 [1] CRAN (R 3.6.1)
 limma            3.42.2  2020-02-03 [1] Bioconductor  
 magrittr       * 2.0.1   2020-11-17 [1] CRAN (R 3.6.1)
 memoise          2.0.0   2021-01-26 [1] CRAN (R 3.6.1)
 mouse430a2.db  * 3.2.3   2021-03-28 [1] Bioconductor  
 mouse430a2cdf  * 2.18.0  2021-03-28 [1] Bioconductor  
 munsell          0.5.0   2018-06-12 [1] CRAN (R 3.6.1)
 openxlsx         4.2.3   2020-10-27 [1] CRAN (R 3.6.1)
 org.Mm.eg.db   * 3.10.0  2021-03-28 [1] Bioconductor  
 pillar           1.5.1   2021-03-05 [1] CRAN (R 3.6.1)
 pkgbuild         1.2.0   2020-12-15 [1] CRAN (R 3.6.1)
 pkgconfig        2.0.3   2019-09-22 [1] CRAN (R 3.6.1)
 pkgload          1.2.0   2021-02-23 [1] CRAN (R 3.6.1)
 plotly         * 4.9.3   2021-01-10 [1] CRAN (R 3.6.1)
 png              0.1-7   2013-12-03 [1] CRAN (R 3.6.1)
 preprocessCore   1.48.0  2019-10-29 [1] Bioconductor  
 prettyunits      1.1.1   2020-01-24 [1] CRAN (R 3.6.1)
 processx         3.5.0   2021-03-23 [1] CRAN (R 3.6.1)
 pryr             0.1.4   2018-02-18 [1] CRAN (R 3.6.1)
 ps               1.6.0   2021-02-28 [1] CRAN (R 3.6.1)
 purrr            0.3.4   2020-04-17 [1] CRAN (R 3.6.1)
 R6               2.5.0   2020-10-28 [1] CRAN (R 3.6.1)
 RColorBrewer     1.1-2   2014-12-07 [1] CRAN (R 3.6.1)
 Rcpp             1.0.6   2021-01-15 [1] CRAN (R 3.6.1)
 readxl           1.3.1   2019-03-13 [1] CRAN (R 3.6.1)
 remotes          2.2.0   2020-07-21 [1] CRAN (R 3.6.1)
 rlang            0.4.10  2020-12-30 [1] CRAN (R 3.6.1)
 rmarkdown        2.7     2021-02-19 [1] CRAN (R 3.6.1)
 rprojroot        2.0.2   2020-11-15 [1] CRAN (R 3.6.1)
 RSQLite          2.2.5   2021-03-27 [1] CRAN (R 3.6.1)
 rstudioapi       0.13    2020-11-12 [1] CRAN (R 3.6.1)
 S4Vectors      * 0.24.4  2020-04-09 [1] Bioconductor  
 sass             0.3.1   2021-01-24 [1] CRAN (R 3.6.1)
 scales         * 1.1.1   2020-05-11 [1] CRAN (R 3.6.1)
 sessioninfo      1.1.1   2018-11-05 [1] CRAN (R 3.6.1)
 stringi          1.5.3   2020-09-09 [1] CRAN (R 3.6.1)
 stringr          1.4.0   2019-02-10 [1] CRAN (R 3.6.1)
 superheat      * 0.1.0   2017-02-04 [1] CRAN (R 3.6.1)
 testthat         3.0.2   2021-02-14 [1] CRAN (R 3.6.1)
 tibble           3.1.0   2021-02-25 [1] CRAN (R 3.6.1)
 tidyr            1.1.3   2021-03-03 [1] CRAN (R 3.6.1)
 tidyselect       1.1.0   2020-05-11 [1] CRAN (R 3.6.1)
 usethis          2.0.1   2021-02-10 [1] CRAN (R 3.6.1)
 utf8             1.2.1   2021-03-12 [1] CRAN (R 3.6.1)
 vctrs            0.3.6   2020-12-17 [1] CRAN (R 3.6.1)
 viridisLite      0.3.0   2018-02-01 [1] CRAN (R 3.6.1)
 withr            2.4.1   2021-01-26 [1] CRAN (R 3.6.1)
 xfun             0.22    2021-03-11 [1] CRAN (R 3.6.1)
 xml2             1.3.2   2020-04-23 [1] CRAN (R 3.6.1)
 yaml             2.2.1   2020-02-01 [1] CRAN (R 3.6.1)
 zip              2.1.1   2020-08-27 [1] CRAN (R 3.6.1)
 zlibbioc         1.32.0  2019-10-29 [1] Bioconductor  

[1] /homedirs26/sghms/bms/users/anohturf/R/x86_64-pc-linux-gnu-library/3.6
[2] /opt/R/3.6.1/lib64/R/library
LS0tCnRpdGxlOiAiQSBub3ZlbCByb2xlIGZvciBhbGt5bGFkZW5pbmUgRE5BIGdseWNvc3lsYXNlIGluIHJlZ3VsYXRpbmcgYWxreWxhdGlvbi1pbmR1Y2VkIEVSIHN0cmVzcyIKc3VidGl0bGU6ICJGaWd1cmUgUzEiCmF1dGhvcjogIkwgTWlsYW5vLCBDRiBDaGFybGllciwgUiBBbmRyZWd1ZXR0aSwgRSBIZWFsaW5nLCBNUCBUaG9tw6ksIFIgRWxsaW90dCwgSlkgTWFzc29uLCBMRCBTYW1zb24sIEcgTGVueiwgSkFQIEhlbnJpcXVlcywgQSBOb2h0dXJmZnQgYW5kIExCIE1laXJhIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogVFJVRQogICAgdG9jX2Zsb2F0OiBUUlVFCiAgICB0b2NfZGVwdGg6IDMKICAgIGNvZGVfZm9sZGluZzogImhpZGUiCiAgICBudW1iZXJfc2VjdGlvbnM6IEZBTFNFCiAgICB0aGVtZTogInJlYWRhYmxlIgogICAgaGlnaGxpZ2h0OiAidGFuZ28iCiAgICBmaWdfY2FwdGlvbjogVFJVRQogICAgY3NzOiAiLi9zb3VyY2Uvc3R5bGVzLmNzcyIKLS0tCgpgYGB7anN9CmZ1bmN0aW9uIG15RnVuY3Rpb24oaWQpIHsKICB2YXIgeCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlkKTsKICBpZiAoeC5zdHlsZS5kaXNwbGF5ID09PSAnbm9uZScpIHsKICAgIHguc3R5bGUuZGlzcGxheSA9ICdibG9jayc7CiAgfSBlbHNlIHsKICAgIHguc3R5bGUuZGlzcGxheSA9ICdub25lJzsKICB9Cn0KYGBgCgo8ZGl2IGNsYXNzPSdjb21tZW50cyc+Ck5vdGU6IFRoaXMgYW5hbHlzaXMgcmVxdWlyZXMgaW5wdXQgZGF0YSBnZW5lcmF0ZWQgYnkgYW4gZWFybGllciBzY3JpcHQuCjwvZGl2PgoKIyMgU2V0dXAgIAoKKiBDbGVhciBtZW1vcnkgYW5kIGNvbnNvbGUgIAoqIExvYWQgcGFja2FnZXMgIAoqIEdldCBjdXJyZW50IHNjcmlwdCBuYW1lICAKCmBgYHtyIENMRUFSIE1FTU9SWSBBTkQgUEFDS0FHRVMgQU5EIENPTlNPTEUsIHJlc3VsdHM9ImhpZGUifQojIENsZWFyIG1lbW9yeQpybShsaXN0PXNldGRpZmYobHMoYWxsPVRSVUUpLCBjKCIuUmFuZG9tLnNlZWQiKSkpCiMgQ2xlYXIgY29uc29sZQpjYXQoIlwwMTQiKQpgYGAKCiMjIFNldCB1cCAgCmBgYHtyIFBhY2thZ2VzLCBpbmNsdWRlPUZBTFNFLCByZXN1bHRzPSJoaWRlIn0KbGlicmFyeShkcGx5cikKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKYGBgCgoKYGBge3IgR2V0IHNjcmlwdCBuYW1lLCAgY2xhc3Mub3V0cHV0PSJ0eHRfb3V0cHV0In0KdGhpcy5zY3JpcHQgPC0gcnN0dWRpb2FwaTo6Z2V0QWN0aXZlRG9jdW1lbnRDb250ZXh0KCkkcGF0aCAlPiUgYmFzZW5hbWUKY2F0KCJTY3JpcHQ6IiwgdGhpcy5zY3JpcHQpCmBgYAoKCmBgYHtyIEZ1bmN0aW9uc18xfQpnZy5nZXQuYnJlYWtzX2J5MSA8LSBmdW5jdGlvbihsaW1pdHMpIHsKICBhIDwtIGZsb29yKGxpbWl0c1sxXSkKICBiIDwtIGNlaWxpbmcobGltaXRzWzJdKQogIHNlcShhLCBiLCBieSA9IDEpCn0KCmdnLmdldC5icmVha3NfYnkyIDwtIGZ1bmN0aW9uKGxpbWl0cykgewogIGEgPC0gZmxvb3IobGltaXRzWzFdKQogIGlmIChhICUlIDIgPT0gMSkgYSA8LSBhIC0gMQogIGIgPC0gY2VpbGluZyhsaW1pdHNbMl0pCiAgaWYgKGIgJSUgMiA9PSAxKSBiIDwtIGIgKyAxCiAgc2VxKGEsIGIsIGJ5ID0gMikKfQpgYGAKCgpgYGB7ciBGdW5jdGlvbnNfMn0KZ2V0LmdnIDwtIGZ1bmN0aW9uKG10cngsIGNvbHVtLm5hbWVzLCBheGlzLmxhYnMsIHRpdHJlLAogICAgICAgICAgICAgICAgICAgIG1hcmtlci5jb2wuZmFsc2UsIG1hcmtlci5jb2wudHJ1ZT0iI0IyMDAwMCIsIG1hcmtlci5hbHBoYT0xLCB0dGFibGUpIHsKCiAgdHRhYmxlMiA8LSBkcGx5cjo6c2VsZWN0KHR0YWJsZSwgUFJPQkVJRCwgU1lNQk9MLCBhZGouUC5WYWwpICU+JSAKICAgIGRwbHlyOjpncm91cF9ieShQUk9CRUlEKSAlPiUKICAgIGRwbHlyOjpzbGljZSh3aGljaC5taW4oYWRqLlAuVmFsKSkgJT4lIAogICAgZHBseXI6OnVuZ3JvdXAoLikKCiAgZGYgPC0gbXRyeFssY29sdW0ubmFtZXNdICU+JSAKICAgIG1hZ3JpdHRyOjpzZXRfY29sbmFtZXMoYXhpcy5sYWJzKSAlPiUgCiAgICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigiUFJPQkVJRCIpCiAgCiAgZGYyIDwtIG1lcmdlKHg9dHRhYmxlMiwgeT1kZiwgYnk9IlBST0JFSUQiLCBhbGwueD1GQUxTRSwgYWxsLnk9VFJVRSkgJT4lIAogICAgZHBseXI6Om11dGF0ZShwLm9rID0gYWRqLlAuVmFsIDw9IDAuMDUpICU+JSAKICAgIGRwbHlyOjptdXRhdGUocC5vayA9IGFzLmNoYXJhY3RlcihwLm9rKSkgJT4lIAogICAgZHBseXI6Om11dGF0ZShwLm9rID0gZmFjdG9yKHAub2ssIGxldmVscz1jKCJGQUxTRSIsICJUUlVFIikpKSAlPiUgCiAgICBkcGx5cjo6bXV0YXRlKElEID0gcGFzdGUwKFNZTUJPTCwgIiAoIiwgUFJPQkVJRCwgIikiKSkgJT4lIAogICAgZHBseXI6OnNlbGVjdCgtUFJPQkVJRCwgLVNZTUJPTCwgLWFkai5QLlZhbCkgJT4lIAogICAgZHBseXI6OnNlbGVjdChJRCwgZXZlcnl0aGluZygpKQoKICByZXMgPC0gZGYyICU+JSAKICAgIGdncGxvdChhZXNfc3RyaW5nKHg9YXhpcy5sYWJzWzFdLCB5PWF4aXMubGFic1syXSkpICsKICAgIGdlb21fcG9pbnQoYWVzKHRleHQ9SUQsIGNvbG9yPXAub2spLCBhbHBoYT1tYXJrZXIuYWxwaGEpICsgIyBjb2xvcj1tYXJrZXIuY29sLmZhbHNlLAogICAgIyBzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lPSJwIOKJpCAwLjA1IikgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKG1hcmtlci5jb2wuZmFsc2UsIG1hcmtlci5jb2wudHJ1ZSksIG5hbWU9InAg4omkIDAuMDUiKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID1jKG1pbihtdHJ4KSwgbWF4KG10cngpKSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9YyhtaW4obXRyeCksIG1heChtdHJ4KSkpICsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgY29sb3I9ImdyZXkyNSIpICsKICAgIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IC1sb2cyKDEuNzUpLCBzbG9wZSA9IDEsIGNvbG9yPSJncmV5MjUiLCBsaW5ldHlwZT0iZGFzaGVkIikgKwogICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gbG9nMigxLjc1KSwgc2xvcGUgPSAxLCBjb2xvcj0iZ3JleTI1IiwgbGluZXR5cGU9ImRhc2hlZCIpICsKICAgIGxhYnModGl0bGUgPSB0aXRyZSkKICByZXMKfQpgYGAKCiMjIExvYWQgZGF0YQojIyMgTG9hZCBtZWFuIGV4cHJlc3Npb24gZGF0YSAgClRhYmxlIGluY2x1ZGVzIHByb2JlIElEcywgZ2VuZSBzeW1ib2xzIGFuZCBnZW5lIG5hbWVzLiAgClByb2JlIElEcyBhbmQgc3ltYm9scyBhcmUgbm90IHVuaXF1ZSAoZHVlIHRvIGdlbmUgc3ltYm9sIG1hcHBpbmcpLiAgCgpgYGB7ciBSZWFkIG1lYW4gZXhwciwgY2xhc3Mub3V0cHV0PSJ0eHRfb3V0cHV0In0KbWVhbi5leHByLmZpbGUgPC0gIi4vZGF0YS8wMV9SYXdfRGF0YV9Qcm9jZXNzaW5nLlJtZC5leHByX21lYW4udHh0IgptYXRyaXguZGYubWVhbiA8LSByZWFkLnRhYmxlKG1lYW4uZXhwci5maWxlLCBzZXA9Ilx0IiwgaGVhZGVyPVQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtU1lNQk9MLCAtR0VORU5BTUUpICU+JSAKICBkcGx5cjo6ZGlzdGluY3QoUFJPQkVJRCwgLmtlZXBfYWxsPVRSVUUpICU+JSAKICB0aWJibGU6OmNvbHVtbl90b19yb3duYW1lcygiUFJPQkVJRCIpCmNhdCgiRmlsZSByZWFkOiIsIG1lYW4uZXhwci5maWxlKQpybShtZWFuLmV4cHIuZmlsZSkKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpoZWFkKG1hdHJpeC5kZi5tZWFuKQpgYGAKCgojIyMgTG9hZCBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgcHJvYmVzIChlZmZlY3Qgb2YgTU1TKSAgCmBgYHtyIFJlYWQgREUgcHJvYmVzLCBjbGFzcy5vdXRwdXQ9InR4dF9vdXRwdXQifQojIGxpc3QuZmlsZXMoImRhdGEiKQpkaWZmLnByb2Jlcy5maWxlIDwtICIuL2RhdGEvMDJfU3VwcGxfVGFibGVfMDEuUm1kLkRFcHJvYmVzLlJEUyIKc3RvcGlmbm90KGZpbGUuZXhpc3RzKGRpZmYucHJvYmVzLmZpbGUpKQp0ZXN0LnJlc3VsdHMucHJvYmVzIDwtIHJlYWRSRFMoZGlmZi5wcm9iZXMuZmlsZSkKY2F0KCJGaWxlIHJlYWQ6IiwgZGlmZi5wcm9iZXMuZmlsZSkKcm0oZGlmZi5wcm9iZXMuZmlsZSkKYGBgCgpgYGB7ciByZXN1bHRzPSJhc2lzIn0KeCA8LSBwYXN0ZSh1dGlsczo6Y2FwdHVyZS5vdXRwdXQoc3RyKHRlc3QucmVzdWx0cy5wcm9iZXMpKSwgY29sbGFwc2U9Ijxicj5cbiIsIHNlcD0iIikKZGV0YWlsczo6ZGV0YWlscyh4LCBzdW1tYXJ5PSJTaG93IHN1bW1hcnkgb2YgREUgcHJvYmVzIiwgbGFuZz1OVUxMKQpybSh4KQpgYGAKCgojIyMgTG9hZCB0b3B0YWJsZXMgIApgYGB7ciBSZWFkIHRvcHRhYmxlcywgY2xhc3Mub3V0cHV0PSJ0eHRfb3V0cHV0In0KIyBsaXN0LmZpbGVzKCkKdHQuZmlsZSA8LSAiU3VwcGxlbWVudGFsX0RhdGFfMS54bHN4IgpzdG9waWZub3QoZmlsZS5leGlzdHModHQuZmlsZSkpCnR0LnNoZWV0Lm5hbWVzIDwtIG9wZW54bHN4OjpnZXRTaGVldE5hbWVzKHR0LmZpbGUpCiMgdHQuc2hlZXQubmFtZXMKIyAia28uY3RybC52cy53dC5jdHJsIiAia28ubW1zLnZzLnd0Lm1tcyIgICAid3QubW1zLnZzLnd0LmN0cmwiICAia28ubW1zLnZzLmtvLmN0cmwiCmdldC54bHN4LmRhdGEgPC0gZnVuY3Rpb24oZmlsLCBzaGVldCkgewogIG9wZW54bHN4OjpyZWFkLnhsc3goeGxzeEZpbGUgPSBmaWwsIHNoZWV0PXNoZWV0KQp9CnR0Lmxpc3QgPC0gbGFwcGx5KHR0LnNoZWV0Lm5hbWVzLCBmdW5jdGlvbih0aGUuc2hlZXQpIHsKICByZXMgPC0gZ2V0Lnhsc3guZGF0YShmaWw9dHQuZmlsZSwgc2hlZXQ9dGhlLnNoZWV0KSAlPiUgCiAgICBkcGx5cjo6c2VsZWN0KFBST0JFSUQsIFNZTUJPTCwgbG9nRkMsIGFkai5QLlZhbCkKICByZXMKfSkgJT4lIAogIHNldF9uYW1lcyh0dC5zaGVldC5uYW1lcykKY2F0KCJGaWxlIHJlYWQ6IiwgdHQuZmlsZSkKcm0odHQuZmlsZSwgdHQuc2hlZXQubmFtZXMpCmBgYAoKCmBgYHtyIHJlc3VsdHM9ImFzaXMifQp5IDwtIHBhc3RlKHV0aWxzOjpjYXB0dXJlLm91dHB1dChzdHIodHQubGlzdCkpLCBjb2xsYXBzZT0iPGJyPlxuIiwgc2VwPSIiKQpkZXRhaWxzOjpkZXRhaWxzKHksIHN1bW1hcnk9IlNob3cgc3VtbWFyeSBvZiB0b3B0YWJsZXMgbGlzdCIsIGxhbmc9TlVMTCkKcm0oeSkKYGBgCgoKIyMgUGxvdCBwcm9iZXMgc3VwcHJlc3NlZCBPUiBpbmR1Y2VkIGJ5IE1NUyBpbiB3aWxkLXR5cGUgT1Iga25vY2tvdXQgICAgCiMjIyBTZWxlY3QgcHJvYmVzIHRvIHBsb3QKYGBge3IgU2VsZWN0IGdlbmVzIHRvIHBsb3QsIGNsYXNzLm91dHB1dD0idHh0X291dHB1dCJ9Cnd0LmtvLmRvd24udXAgPC0gc29ydCh1bmlxdWUodW5saXN0KHRlc3QucmVzdWx0cy5wcm9iZXMpKSkKc3RvcGlmbm90KCFhbnkoaXMubmEod3Qua28uZG93bi51cCkpKQpjYXQoIlByb2JlcyBzZWxlY3RlZDoiLCBsZW5ndGgod3Qua28uZG93bi51cCkpCmBgYAoKCgpgYGB7ciByZXN1bHRzPSJoaWRlIn0KIyBtYXRyaXguZGYubWVhblsxOjQsMTo0XQpteC53dC5rby5kb3duLnVwIDwtIG1hdHJpeC5kZi5tZWFuW3d0LmtvLmRvd24udXAsXQpkaW0obXgud3Qua28uZG93bi51cCkKYGBgCgoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KZ2cuNi40IDwtIGdldC5nZyhtdHJ4PW14Lnd0LmtvLmRvd24udXAsCiAgICAgICBjb2x1bS5uYW1lcyA9IGMoIld0X0N0cmwiLCAiS29fQ3RybCIpLAogICAgICAgYXhpcy5sYWJzID0gYygiV1QiLCAiS08iKSwKICAgICAgIHRpdHJlID0gIkNvbnRyb2w6IEtub2Nrb3V0IHZlcnN1cyBXaWxkLXR5cGUiLAogICAgICAgbWFya2VyLmNvbC5mYWxzZSA9ICIjMDA1QUI1IiwgIyBicFszXQogICAgICAgbWFya2VyLmNvbC50cnVlID0gIiNEQzMyMjAiLAogICAgICAgbWFya2VyLmFscGhhPTAuNSwKICAgICAgIHR0YWJsZT10dC5saXN0JGtvLmN0cmwudnMud3QuY3RybCkKZ2cuNi40YiA8LSBnZy42LjQgKyAKICB0aGVtZV9jbGFzc2ljKCkgKwogIGNvb3JkX2VxdWFsKCkKZ2dwbG90bHkoZ2cuNi40YikKYGBgCgoKYGBge3IgY2xhc3Mub3V0cHV0PSJ0eHRfb3V0cHV0In0Kb3V0LmZpbGUucGRmIDwtICJGaWd1cmVfUzEucGRmIgpnZ3NhdmUoZmlsZW5hbWU9b3V0LmZpbGUucGRmLCBwbG90ID0gZ2cuNi40Yiwgd2lkdGggPSAxMCwgaGVpZ2h0PTEwLCB1bml0cyA9ICJjbSIpCmNhdCgiU2F2ZWQ6Iiwgb3V0LmZpbGUucGRmKQpgYGAKCgojIyMgU2Vzc2lvbiBpbmZvICAKCjxidXR0b24gY2xhc3M9ImJ1dHRvbiIgb25jbGljaz0ibXlGdW5jdGlvbignRElWXzEnKSI+U2hvdy9oaWRlIHNlc3Npb24gaW5mbzwvYnV0dG9uPgo8ZGl2IGlkPSJESVZfMSIgY2xhc3M9ImRpdl9kZWZhdWx0X2hpZGUiPgoKYGBge3IgU0VTU0lPTiBJTkZPIERBVEUsIHJlc3VsdHM9ImFzaXMifQpjYXQoIkRhdGU6IiwgZm9ybWF0KFN5cy50aW1lKCksICIlYSAlZC0lYi0lWSAlSDolTTolUyIpLCAiPGJyPlxuIikKYGBgCgpgYGB7ciBwcmludF9zZXNzaW9uX2luZm8sIFIub3B0aW9ucz1saXN0KHdpZHRoPTcwKX0KZGV2dG9vbHM6OnNlc3Npb25faW5mbygpCmBgYAo8L2Rpdj4KICAKYGBge2pzfQp2YXIgZGl2c1RvSGlkZSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoImRpdl9kZWZhdWx0X2hpZGUiKTsKZm9yKHZhciBpID0gMDsgaSA8IGRpdnNUb0hpZGUubGVuZ3RoOyBpKyspCnsKICBkaXZzVG9IaWRlW2ldLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7Cn0KYGBgCgoKCg==